﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security.Policy;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media.Imaging;
using AngleSharp.Html.Dom;
using AngleSharp.Html.Parser;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using NeteaseCloudMusicApi;
using NetEaseVipDefense.Model;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using StackExchange.Redis;

namespace NetEaseVipDefense.ViewModel
{

    /// <summary>
    /// This class contains properties that the main View can data bind to.
    /// <para>
    /// See http://www.mvvmlight.net
    /// </para>
    /// </summary>
    public class MainViewModel : ViewModelBase
    {
        private readonly IDataService _dataService;


        private int pages = 0;
        private HtmlParser parser = new HtmlParser();
        public static HttpClient Client =
            new HttpClient(new HttpClientHandler() { AutomaticDecompression = DecompressionMethods.GZip });
        private string _ExtendName = ".flac";

        public string ExtendName
        {
            get { return _ExtendName; }
            set
            {
                _ExtendName = value;
                RaisePropertyChanged("ExtendName");
            }
        }

        private string keyWord = "词不达意";

        public string KeyWord
        {
            get { return keyWord; }
            set
            {
                keyWord = value;
                RaisePropertyChanged("KeyWord");
                SearchCommand.RaiseCanExecuteChanged();
            }
        }

        async Task SearchAsync(SongModel song)
        {
            var time = 1000 * (new Random()).Next(1, 6);
            Console.WriteLine($"休眠{time}");
            Console.WriteLine($"开始搜索{song}");
            //Thread.Sleep(time);
            if (string.IsNullOrEmpty(song.ToString()))
            {
                return;
            }
            var formattableString = $"http://www.daihema.com/s/name/{song.ToString()}{ExtendName}";
            Console.WriteLine(formattableString);
            var tempstr = "";
            int index = 0;
            try
            {
                tempstr = await Client.GetStringAsync(formattableString);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                var webProxy = new WebProxy(ProxyHelper.GetNextProxy());
                Client = new HttpClient(new HttpClientHandler()
                {
                    AutomaticDecompression = DecompressionMethods.GZip,
                    Proxy = webProxy

                });
            }
            IHtmlDocument tempdoc = await parser.ParseDocumentAsync(tempstr);
            var num = tempdoc.QuerySelector(".search-page")?.QuerySelectorAll(".red.sep-both05.bold")?.LastOrDefault()?.TextContent;
            if (string.IsNullOrEmpty(num) || num == "0")
            {
                //MessageBox.Show("搜索结果为空", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }
            var numberOfResults = Convert.ToInt32(num);
            pages = numberOfResults % 30 == 0 ? numberOfResults / 30 : numberOfResults / 30 + 1;
            song.BaiduFileModels = new ObservableCollection<BaiduFileModel>();
            song.BaiduFileModels.Clear();
            var key = song.ToString();
            await Task.Run(() =>
            {
                for (int i = 1; i <= pages && i < 5; i++)
                {
                    Console.WriteLine($"{song}页面数量:{pages},当前i={i}");
                    try
                    {
                        var str = Client.GetStringAsync("http://www.daihema.com/s/name/" + key + "/" + i).Result;
                        IHtmlDocument doc = parser.ParseDocumentAsync(str).Result;
                        var results = doc.QuerySelectorAll(".row").Select(element =>
                        {
                            var tempStr = element.QuerySelector(".small").TextContent;
                            var index1 = tempStr.IndexOf("发布");
                            var data = tempStr.Substring(index1 - 10, 10);
                            if (data.Contains(" ") || data.Contains("今天"))
                            {
                                data = tempStr.Substring(index1 - 5, 5);
                            }
                            DateTime temp = default;
                            if (data.Length == 10)
                            {
                                temp = Convert.ToDateTime(data);
                            }
                            else if (data.Length == 5)
                            {
                                if (data.Contains(":"))
                                {
                                    temp = DateTime.Now.Date;
                                }
                                else
                                {
                                    temp = DateTime.Parse(DateTime.Now.Year + "-" + data);
                                }
                            }
                            return new BaiduFileModel()
                            {
                                Title = element.QuerySelector("a").GetAttribute("title"),
                                Author = element.QuerySelector(".small").LastChild.TextContent,
                                Size = element.QuerySelector(".size").TextContent,
                                Time = temp.ToShortDateString().ToString(),
                                Url = element.QuerySelector("a").GetAttribute("href"),
                            };
                        });
                        song.BaiduFileModels = new ObservableCollection<BaiduFileModel>(song.BaiduFileModels.Concat(results));
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e);
                    }

                }
            });
            //初始化页数 
            song.BaiduFileModels = new ObservableCollection<BaiduFileModel>(song.BaiduFileModels.OrderByDescending(o => o.Time).ToList());

        }

        private RelayCommand getRealUrlCommand;
        private RelayCommand _autoCommand;
        private RelayCommand saveCommand;

        /// <summary>
        /// Gets the SaveCommand.
        /// </summary>
        public RelayCommand SaveCommand
        {
            get
            {
                return saveCommand
                    ?? (saveCommand = new RelayCommand(
                    () =>
                    {
                        List<string> datas = new List<string>();
                        foreach (var song in Songs)
                        {
                            datas.Add($"{song.BaduCloudDiskUrl},{song.ToString()}");
                        }
                        File.WriteAllLines("data.csv", datas);
                    }));
            }
        }
        /// <summary>
        /// Gets the AutoCommand.
        /// </summary>
        public RelayCommand AutoCommand
        {
            get
            {
                return _autoCommand
                    ?? (_autoCommand = new RelayCommand(
                    async () =>
                    {
                        foreach (var song in Songs)
                        {
                            await SearchAsync(song);

                        }
                    }));
            }
        }
        private RelayCommand _searchCommand;

        /// <summary>
        /// Gets the SearchCommand.
        /// </summary>
        public RelayCommand SearchCommand
        {
            get
            {
                return _searchCommand
                       ?? (_searchCommand = new RelayCommand(
                           async () =>
                           {
                               await SearchAsync(SelectedSong);

                           }/*,()=> { return !string.IsNullOrWhiteSpace(KeyWord); }*/));
            }
        }
        /// <summary>
        /// Gets the GetRealUrlCommand.
        /// </summary>
        public RelayCommand GetRealUrlCommand
        {
            get
            {
                return getRealUrlCommand
                    ?? (getRealUrlCommand = new RelayCommand(
                        async () =>
                        {

                            await SelectedSong.SelectedBaiduFileModel.GetRealUrlAsync();

                            try
                            {
                                SelectedSong.BaduCloudDiskUrl = SelectedSong.SelectedBaiduFileModel.FileRealPageUrl;
                                Clipboard.SetDataObject(SelectedSong.SelectedBaiduFileModel.FileRealPageUrl);
                            }
                            catch (Exception e)
                            {
                                Console.WriteLine(e);
                            }

                        }));
            }
        }
        /// <summary>
        /// Initializes a new instance of the MainViewModel class.
        /// </summary>
        public MainViewModel(IDataService dataService)
        {
            //GetSongListData();
            _dataService = dataService;
            _dataService.GetData(
                (item, error) =>
                {
                    if (error != null)
                    {
                        // Report error here
                        return;
                    }

                });
            // get proxy list

            // check all proxies

        }

        private ObservableCollection<SongModel> songs;

        public ObservableCollection<SongModel> Songs
        {
            get { return songs; }
            set
            {
                songs = value;
                RaisePropertyChanged("Songs");
            }
        }

        private SongModel selectedSong;

        public SongModel SelectedSong
        {
            get { return selectedSong; }
            set
            {
                if (value != null)
                {
                    selectedSong = value;
                    // KeyWord =value.Artist+" "+ value.Name + "&f-flac ape";
                    KeyWord = value.ToString();
                    RaisePropertyChanged("SelectedSong");
                }
            }
        }



        private RelayCommand getMySongsCommand;

        /// <summary>
        /// Gets the GetMySongsCommand.
        /// </summary>
        public RelayCommand GetMySongsCommand
        {
            get
            {
                return getMySongsCommand
                    ?? (getMySongsCommand = new RelayCommand(
                    () =>
                    {
                        try
                        {
                            GetSongListData();
                        }
                        catch (Exception e)
                        {
                            MessageBox.Show(e.Message);
                        }
                    }));
            }
        }

        public UserInfo UserInfo { get; set; } = new UserInfo() { UserName = "17682487263", Password = "" };
        public async void GetSongListData()
        {
            using (CloudMusicApi api = new CloudMusicApi())
            {
                try
                {
                    bool isOk;
                    JObject json;
                    int uid;
                    int[] trackIds;
                    /******************** 登录 ********************/
                    do
                    {
                        Dictionary<string, string> queries;
                        string account;
                        bool isPhone;

                        queries = new Dictionary<string, string>();

                        account = UserInfo.UserName;
                        isPhone = Regex.Match(account, "^[0-9]+$").Success;
                        queries[isPhone ? "phone" : "email"] = account;

                        queries["password"] = UserInfo.Password;
                        (isOk, json) = await api.RequestAsync(isPhone ? CloudMusicApiProviders.LoginCellphone : CloudMusicApiProviders.Login, queries);
                        if (!isOk)
                            Console.WriteLine("登录失败，账号或密码错误");
                    } while (!isOk);
                    Console.WriteLine("登录成功");
                    Console.WriteLine();

                    /******************** 登录 ********************/

                    /******************** 获取账号信息 ********************/

                    (isOk, json) = await api.RequestAsync(CloudMusicApiProviders.LoginStatus, CloudMusicApi.EmptyQueries);
                    if (!isOk)
                        throw new ApplicationException($"获取账号信息失败： {json}");
                    uid = (int)json["profile"]["userId"];
                    Console.WriteLine($"账号ID： {uid}");
                    Console.WriteLine($"账号昵称： {json["profile"]["nickname"]}");
                    Console.WriteLine();

                    /******************** 获取账号信息 ********************/

                    /******************** 获取我喜欢的音乐 ********************/

                    (isOk, json) = await api.RequestAsync(CloudMusicApiProviders.UserPlaylist, new Dictionary<string, string> { { "uid", uid.ToString() } });
                    if (!isOk)
                        throw new ApplicationException($"获取用户歌单失败： {json}");
                    (isOk, json) = await api.RequestAsync(CloudMusicApiProviders.PlaylistDetail, new Dictionary<string, string> { { "id", json["playlist"][0]["id"].ToString() } });
                    if (!isOk)
                        throw new ApplicationException($"获取歌单详情失败： {json}");
                    trackIds = json["playlist"]["trackIds"].Select(t => (int)t["id"]).ToArray();
                    (isOk, json) = await api.RequestAsync(CloudMusicApiProviders.SongDetail, new Dictionary<string, string> { { "ids", string.Join(",", trackIds) } });
                    if (!isOk)
                        throw new ApplicationException($"获取歌曲详情失败： {json}");
                    Console.WriteLine($"我喜欢的音乐 （{trackIds.Length} 首）：");


                    List<SongModel> ss = JsonConvert.DeserializeObject<List<SongModel>>(json["songs"].ToString());
                    Songs = new ObservableCollection<SongModel>(ss);
                    Console.WriteLine(json["songs"]);
                    /******************** 获取我喜欢的音乐 ********************/

                    /******************** 退出登录 ********************/

                    (isOk, json) = await api.RequestAsync(CloudMusicApiProviders.Logout, CloudMusicApi.EmptyQueries);
                    if (!isOk)
                        throw new ApplicationException($"退出登录失败： {json}");
                    Console.WriteLine("退出登录成功");
                    Console.WriteLine();

                    /******************** 退出登录 ********************/
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex);
                }
            }
        }

        ////public override void Cleanup()
        ////{
        ////    // Clean up if needed

        ////    base.Cleanup();
        ////}
    }
    public class NullToBooleanConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value == null) return false;
            if (string.IsNullOrWhiteSpace(value.ToString()))
            {
                return false;
            }
            PropertyInfo propertyInfo = value.GetType().GetProperty("Count");
            if (propertyInfo != null)
            {
                int count = (int)propertyInfo.GetValue(value, null);
                return count > 0;
            }
            if (!(value is bool || value is bool?)) return true;
            return value;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return value;
        }
    }

    public class BaiduFileModel : INotifyPropertyChanged
    {
        public static int InstanceCount = 0;
        private HttpClient Client = new HttpClient(new HttpClientHandler()
        {
            AutomaticDecompression = DecompressionMethods.GZip,
            //  Proxy=new WebProxy("117.88.177.67", 3000) 
        });
        private string _url;

        public string Title { get; set; }

        public string Author { get; set; }

        public string Size { get; set; }

        public string Time { get; set; }

        public string Url
        {
            get => _url;
            set
            {
                _url = value;
                //GetRealUrlAsync();
            }
        }

        public string FullRul => "http://pdd.19mi.net/go" + Url.Substring(Url.LastIndexOf('/'));
        private string _FileRealPageUrl;

        public string FileRealPageUrl
        {
            get { return _FileRealPageUrl; }
            set
            {
                _FileRealPageUrl = value;
                RaisePropertyChanged("FileRealPageUrl");
            }
        }

        public BaiduFileModel()
        {
            InstanceCount++;
        }
        public async Task GetRealUrlAsync()
        {
            //Thread.Sleep(1000);
            var temp = await Client.GetStringAsync(this.FullRul);
            while (temp.Contains("验证码"))
            {
                Console.WriteLine("api访问过度,切换IP");
                var webProxy = new WebProxy(ProxyHelper.GetNextProxy());
                Console.WriteLine($"新IP{webProxy.ToString()}");
                Client = new HttpClient(new HttpClientHandler()
                {
                    AutomaticDecompression = DecompressionMethods.GZip,
                    Proxy = webProxy
                });
                temp = await Client.GetStringAsync(this.FullRul);
            }

            var arr = temp.Split('\'');
            FileRealPageUrl = arr.First(t => t.Contains(@"https://pan.baidu.com"));
            Console.WriteLine(FileRealPageUrl);
            try
            {//验证是否过期.
                var data = await Client.GetStringAsync(this.FileRealPageUrl);
                if (data.Contains("啊哦"))
                {
                    Console.WriteLine("文件已过期");
                    FileRealPageUrl = "文件已过期";
                }
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message);
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void RaisePropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

    }
    public class UserInfo
    {
        [DisplayName("用户名")]
        public string UserName { get; set; } = "17682487263";
        [DataType(DataType.Password)]
        [DisplayName("密码")]
        public string Password { get; set; } = "";
    }
    public class ArItem
    {
        /// <summary>
        /// 
        /// </summary>
        public int id { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public string name { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public List<string> tns { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public List<string> alias { get; set; }
    }

    public class Al
    {
        /// <summary>
        /// 
        /// </summary>
        public int id { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public string name { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public string picUrl { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public List<string> tns { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public long pic { get; set; }
    }

    public class H
    {
        /// <summary>
        /// 
        /// </summary>
        public int br { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public int fid { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public int size { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public double vd { get; set; }
    }

    public class M
    {
        /// <summary>
        /// 
        /// </summary>
        public int br { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public int fid { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public int size { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public double vd { get; set; }
    }

    public class L
    {
        /// <summary>
        /// 
        /// </summary>
        public int br { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public int fid { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public int size { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public double vd { get; set; }
    }

    public class Pc
    {
        /// <summary>
        /// 
        /// </summary>
        public string nickname { get; set; }
        /// <summary>
        /// Kiss - 因为是女子.ape
        /// </summary>
        public string fn { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public string cid { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public int uid { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public string ar { get; set; }
        /// <summary>
        /// Kiss - 因为是女子
        /// </summary>
        public string sn { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public int br { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public string alb { get; set; }
    }

    public class SongModel : ViewModelBase
    {
        private ObservableCollection<BaiduFileModel> baiduFileModels = new ObservableCollection<BaiduFileModel>();
        [JsonIgnore]
        public ObservableCollection<BaiduFileModel> BaiduFileModels
        {
            get { return baiduFileModels; }
            set
            {
                baiduFileModels = value;
                RaisePropertyChanged("BaiduFileModels");
            }
        }
        private string _BaduCloudDiskUrl;

        public string BaduCloudDiskUrl
        {
            get { return _BaduCloudDiskUrl; }
            set
            {
                _BaduCloudDiskUrl = value;
                RaisePropertyChanged("BaduCloudDiskUrl");
            }
        }

        private BaiduFileModel selectedBaiduFileModel;
        [JsonIgnore]
        public BaiduFileModel SelectedBaiduFileModel
        {
            get { return selectedBaiduFileModel; }
            set
            {
                selectedBaiduFileModel = value;
                RaisePropertyChanged("SelectedBaiduFileModel");
            }
        }

        public override string ToString()
        {
            return name + " " + string.Join(" ", this.ar.Select(t => t.name));
        }

        /// <summary>
        /// 因为是女子
        /// </summary>
        public string name { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public int id { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public int pst { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public int t { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public List<ArItem> ar { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public List<string> alia { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public double pop { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public int st { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public string rt { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public int fee { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public int v { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public string crbt { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public string cf { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public Al al { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public int dt { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public H h { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public M m { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public L l { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public string a { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public string cd { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public int no { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public string rtUrl { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public int ftype { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public List<string> rtUrls { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public int djId { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public int copyright { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public int s_id { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public long mark { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public int originCoverType { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public int mv { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public int rtype { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public string rurl { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public int mst { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public int cp { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public long publishTime { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public Pc pc { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public List<string> tns { get; set; }
    }


    class Program
    {
        static bool finishIsCompleted = true;
        static ConcurrentDictionary<string, int> failStatis;//保存请求失败的ip地址:key 失败次数：value
        static string refreshLink = "https://blog.csdn.net/baijifeilong/article/details/80734388";
        static string requestSuccessKey, requestFailKey;
        static async Task Main(string[] args)
        {

            ThreadPool.SetMinThreads(500, 100);
            failStatis = new ConcurrentDictionary<string, int>();
            requestSuccessKey = "list_request_success" + DateTime.Now.ToString("hhmm");
            requestFailKey = "list_request_fail" + DateTime.Now.ToString("hhmm");
            Timer timer = new Timer(async (state) =>
            {
                if (finishIsCompleted)
                {
                    finishIsCompleted = false;
                    //获取代理
                    var proxyIps = RedisHelper.GetProxy();
                    int threadCount = 1;
                    if (proxyIps.Count > 10)
                    {
                        threadCount = proxyIps.Count / 10;
                    }
                    //平均分配给每个thread执行15个请求
                    int requestCount = proxyIps.Count / threadCount;
                    for (var i = 0; i < threadCount; i++)
                    {
                        var tempList = proxyIps.GetRange(i * requestCount, requestCount);
                        if (i == threadCount - 1)
                        {
                            tempList.AddRange(proxyIps.GetRange(threadCount * requestCount, proxyIps.Count - threadCount * requestCount));
                        }
                        Thread thread = new Thread(async () =>
                        {
                            //执行发起请求
                            await Finish(tempList);
                        });
                        thread.Start();
                    }
                }
            }, "processing timer event", 0, 1000 * 30);
            Console.ReadLine();
        }

        public static async Task Finish(List<string> proxyIps)
        {
            for (int i = 0; i < proxyIps.Count; i++)
            {
                string ip = proxyIps[i];
                int index = ip.IndexOf(":");
                string ipAddress = ip.Substring(0, index);
                int ipPort = int.Parse(ip.Substring(index + 1));
                //随机休眠
                //Thread.Sleep(new Random().Next(1, 4) * 1000);
                await Get(ipAddress, ipPort, 10000, randomUseragent(), refreshLink, () =>
                {
                    RedisHelper.AddRequestOk(requestSuccessKey, ip + " " + DateTime.Now.ToShortTimeString(), true);
                    Console.ForegroundColor = ConsoleColor.White;
                    Console.WriteLine(ip + " success");
                },
                (error) =>
                {
                    RedisHelper.AddRequestOk(requestFailKey, ip + " " + DateTime.Now.ToShortTimeString(), false);
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.WriteLine(ipAddress + error + "失败" + (failStatis.ContainsKey(ip) ? failStatis[ip] : 1) + "次");
                    if (failStatis.ContainsKey(ip))
                    {
                        if (failStatis[ip] == 6)
                        {
                            RedisHelper.RemoveSetValue(ip);
                        }
                        else
                            failStatis[ip]++;
                    }
                    else
                    {
                        failStatis.AddOrUpdate(ip, 1, (key, oldValue) => oldValue + 1);
                    }
                }
                );
            }
            finishIsCompleted = true;
        }

        private static string randomUseragent()
        {
            string[] usersagents = new string[] {
            "Mozilla/5.0 (Linux; U; Android 2.3.7; en-us; Nexus One Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
            "MQQBrowser/26 Mozilla/5.0 (Linux; U; Android 2.3.7; zh-cn; MB200 Build/GRJ22; CyanogenMod-7) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
            "JUC (Linux; U; 2.3.7; zh-cn; MB200; 320*480) UCWEB7.9.3.103/139/999",
            "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:7.0a1) Gecko/20110623 Firefox/7.0a1 Fennec/7.0a1",
            "Opera/9.80 (Android 2.3.4; Linux; Opera Mobi/build-1107180945; U; en-GB) Presto/2.8.149 Version/11.10",
            "Mozilla/5.0 (Linux; U; Android 3.0; en-us; Xoom Build/HRI39) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13",
            "Mozilla/5.0 (iPhone; U; CPU iPhone OS 3_0 like Mac OS X; en-us) AppleWebKit/420.1 (KHTML, like Gecko) Version/3.0 Mobile/1A542a Safari/419.3",
            "Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_0 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7",
            "Mozilla/5.0 (iPad; U; CPU OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B334b Safari/531.21.10",
            "Mozilla/5.0 (BlackBerry; U; BlackBerry 9800; en) AppleWebKit/534.1+ (KHTML, like Gecko) Version/6.0.0.337 Mobile Safari/534.1+",
            "Mozilla/5.0 (hp-tablet; Linux; hpwOS/3.0.0; U; en-US) AppleWebKit/534.6 (KHTML, like Gecko) wOSBrowser/233.70 Safari/534.6 TouchPad/1.0",
            "Mozilla/5.0 (SymbianOS/9.4; Series60/5.0 NokiaN97-1/20.0.019; Profile/MIDP-2.1 Configuration/CLDC-1.1) AppleWebKit/525 (KHTML, like Gecko) BrowserNG/7.1.18124",
            "Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; Titan)",
            "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36",
            "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.1 Safari/537.36",
            "Mozilla/5.0 (X11; U; Linux x86_64; zh-CN; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10",
            "Mozilla/5.0 (Windows NT 5.1; U; en; rv:1.8.1) Gecko/20061208 Firefox/2.0.0 Opera 9.50",
            "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.57.2 (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2",
            "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36",
            "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; LBBROWSER) ",
            "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; QQBrowser/7.0.3698.400)",
            "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.122 UBrowser/4.0.3214.0 Safari/537.36",
            "Mozilla/5.0 (Linux; U; Android 2.2.1; zh-cn; HTC_Wildfire_A3333 Build/FRG83D) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
            "Mozilla/5.0 (BlackBerry; U; BlackBerry 9800; en) AppleWebKit/534.1+ (KHTML, like Gecko) Version/6.0.0.337 Mobile Safari/534.1+",
            "Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; Titan)",
            "Mozilla/4.0 (compatible; MSIE 6.0; ) Opera/UCWEB7.0.2.37/28/999",
            "Openwave/ UCWEB7.0.2.37/28/999",
            "NOKIA5700/ UCWEB7.0.2.37/28/999",
            "UCWEB7.0.2.37/28/999",
            "Mozilla/5.0 (hp-tablet; Linux; hpwOS/3.0.0; U; en-US) AppleWebKit/534.6 (KHTML, like Gecko) wOSBrowser/233.70 Safari/534.6 TouchPad/1.0",
            "Mozilla/5.0 (Linux; U; Android 3.0; en-us; Xoom Build/HRI39) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13",
            "Opera/9.80 (Android 2.3.4; Linux; Opera Mobi/build-1107180945; U; en-GB) Presto/2.8.149 Version/11.10",
            "Mozilla/5.0 (iPad; U; CPU OS 4_3_3 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5",
            };
            Random random = new Random();
            var randomNumber = random.Next(0, usersagents.Length);
            return usersagents[randomNumber];
        }
        public static async Task Get(string proxyIp, int proxyPort, int timeout, string randomUseragent, string url, Action success, Action<string> fail)
        {
            HttpWebRequest request = null;
            HttpWebResponse response = null;
            try
            {
                request = (HttpWebRequest)WebRequest.Create(url);
                request.Timeout = timeout;
                request.UserAgent = randomUseragent;
                request.Proxy = new WebProxy(proxyIp, proxyPort);

                response = await request.GetResponseAsync() as HttpWebResponse;

                if (response.StatusCode == HttpStatusCode.OK)
                {
                    success();
                }
                else
                {
                    fail(response + ":" + response.StatusDescription);
                }
            }
            catch (Exception ex)
            {
                fail(ex.Message.ToString());
            }
            finally
            {
                if (request != null)
                {
                    request.Abort();
                    request = null;
                }
                if (response != null)
                {
                    response.Close();
                    response = null;
                }
            }
        }
    }
    public class RedisHelper
    {
        private static readonly object Locker = new object();
        private static ConnectionMultiplexer _redis;
        private const string CONNECTTIONSTRING = "127.0.0.1:6379,DefaultDatabase=3";
        public const string REDIS_SET_KET_SUCCESS = "set_success_ip";
        private static ConnectionMultiplexer Manager
        {
            get
            {
                if (_redis == null)
                {
                    lock (Locker)
                    {
                        if (_redis != null) return _redis;
                        _redis = GetManager();
                        return _redis;
                    }
                }
                return _redis;
            }
        }
        private static ConnectionMultiplexer GetManager(string connectionString = null)
        {
            if (string.IsNullOrEmpty(connectionString))
            {
                connectionString = CONNECTTIONSTRING;
            }
            return ConnectionMultiplexer.Connect(connectionString);
        }
        public static void AddRequestOk(string key, string value, bool isSuccess)
        {
            var db = Manager.GetDatabase();
            if (isSuccess)
                db.ListLeftPush(key, value);
            else
                db.ListLeftPush(key, value);
        }
        public static List<string> GetProxy()
        {
            List<string> result = new List<string>();
            var db = Manager.GetDatabase();
            var values = db.SetMembers(REDIS_SET_KET_SUCCESS);
            foreach (var value in values)
            {
                result.Add(value.ToString());
            }
            return result;
        }
        public static bool InsertSet(string value)
        {
            var db = Manager.GetDatabase();
            return db.SetAdd(REDIS_SET_KET_SUCCESS, value);
        }
        public static bool RemoveSetValue(string value)
        {
            var db = Manager.GetDatabase();
            return db.SetRemove(REDIS_SET_KET_SUCCESS, value);
        }
    }


}